home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus Special 26
/
AMIGAplus Sonderheft 26 (2000)(Falke)(DE)(Track 1 of 2)[!].iso
/
Tools
/
SFX-Player
/
Mpeg
/
mpegaudio_datatype
/
dispatch.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-03-29
|
19KB
|
609 lines
/*
**
** $VER: dispatch.c 1.1 (9.11.97)
** mpegaudio.datatype 1.1
**
** Dispatch routine for a DataTypes class
**
** Written 1996/97 by Roland 'Gizzy' Mainz
** Original example source from David N. Junod
**
*/
/* main includes */
#include "classbase.h"
#include "classdata.h"
/*****************************************************************************/
/* This switch would modify the datatype to use "mpega" */
#if 0
#define USE_MPEGA 1
#endif
/*****************************************************************************/
/* local prototypes */
static LONG LoadSample( struct ClassBase *, Object * );
static void mysprintf( struct ClassBase *, STRPTR, STRPTR, ... );
#ifndef NO_ENCODER
static ULONG SaveMPEGAudio( struct ClassBase *, Object *, struct dtWrite * );
#endif /* NO_ENCODER */
/*****************************************************************************/
/* Create "mpegaudio.datatype" BOOPSI class */
struct IClass *initClass( struct ClassBase *cb )
{
struct IClass *cl;
/* Create our class... */
if( cl = MakeClass( MPEGAUDIODTCLASS, SOUNDDTCLASS, NULL, (ULONG)sizeof( struct MPEGAudioInstData ), 0UL ) )
{
#define DTSTACKSIZE (16384UL)
cl -> cl_Dispatcher . h_Entry = (HOOKFUNC)StackSwapDispatch; /* see stackswap.c */
cl -> cl_Dispatcher . h_SubEntry = (HOOKFUNC)Dispatch; /* see stackswap.c */
cl -> cl_Dispatcher . h_Data = (APTR)DTSTACKSIZE; /* see stackswap.c */
cl -> cl_UserData = (ULONG)cb; /* class library base as expected by datatypes.library */
AddClass( cl );
}
return( cl );
}
/*****************************************************************************/
/* class dispatcher */
DISPATCHERFLAGS
ULONG Dispatch( REGA0 struct IClass *cl, REGA2 Object *o, REGA1 Msg msg )
{
struct ClassBase *cb = (struct ClassBase *)(cl -> cl_UserData);
ULONG retval = 0UL;
switch( msg -> MethodID )
{
/****** mpegaudio.datatype/OM_NEW ********************************************
*
* NAME
* OM_NEW -- Create a mpegaudio.datatype object.
*
* FUNCTION
* The OM_NEW method is used to create an instance of the
* mpegaudio.datatype class. This method is passed to the superclass
* first. After this, mpegaudio.datatype loads the sample using
* "mpega" and the 8svx.datatype.
*
* ATTRIBUTES
* The following attributes can be specified at creation time.
*
* DTA_SourceType (ULONG) -- Determinates the type of DTA_Handle
* attribute. Only DTST_FILE is supported.
* If any other type was set in a given DTA_SourceType,
* OM_NEW will be rejected.
* Defaults to DTST_FILE.
*
* DTA_Handle -- For DTST_FILE, a BPTR to a lock is expected by
* datatypesclass, which will convert this into a filehandle.
* A DTST_RAM (create empty object) source type requires a NULL
* handle.
*
* NOTE
* If the datatype was compiled with the NO_ENCODER flag set,
* DTA_SourceType == DTST_RAM causes OM_NEW to reject the method.
*
* RESULT
* If the object was created a pointer to the object is returned,
* otherwise NULL is returned.
*
******************************************************************************
*
*/
case OM_NEW:
{
struct TagItem *ti;
/* We only support DTST_FILE or DTST_RAM as source type */
if( ti = FindTagItem( DTA_SourceType, (((struct opSet *)msg) -> ops_AttrList) ) )
{
if( ((ti -> ti_Data) != DTST_FILE)
#ifndef NO_ENCODER
&& ((ti -> ti_Data) != DTST_RAM)
#endif /* !NO_ENCODER */
)
{
SetIoErr( ERROR_OBJECT_WRONG_TYPE );
break;
}
}
/* This must not be a subclass of mpegaudio.datatype
* (not implemented yet)
*/
if( o == (Object *)cl )
{
if( retval = DoSuperMethodA( cl, o, msg ) )
{
LONG error;
/* Load sample... */
if( error = LoadSample( cb, (Object *)retval ) )
{
/* Something went fatally wrong, dispose object */
CoerceMethod( cl, (Object *)retval, OM_DISPOSE );
retval = 0UL;
}
SetIoErr( error );
}
}
else
{
/* Subclasses of mpegaudio.datatype are not implemented */
SetIoErr( ERROR_NOT_IMPLEMENTED );
}
}
break;
/****** mpegaudio.datatype/OM_DISPOSE ****************************************
*
* NAME
* OM_DISPOSE -- Delete object
*
* FUNCTION
* Frees the contents of the mpegvideo.datatype instance data
* and passes then the msg to the superclass.
*
* This method deletes the embedded 8svx.datatype object and deletes
* the temporary 8SVX sample file created.
*
* RESULT
* Returns 0 evertimes.
*
******************************************************************************
*
*/
case OM_DISPOSE:
{
struct MPEGAudioInstData *maid = (struct MPEGAudioInstData *)INST_DATA( cl, o );
LONG saved_ioerr = IoErr(); /* save I/O error */
/* Any embedded 8SVX/AIFF object ? */
#ifdef USE_MPEGA
if( maid -> maid_AIFFObject )
{
/* Avoid that we free the sample data which belongs to the aiff.datatype object */
SetDTAttrs( o, NULL, NULL, SDTA_Sample, NULL, TAG_DONE );
DisposeDTObject( (maid -> maid_AIFFObject) );
}
/* Delete tmp AIFF file if we created one... */
if( strlen( (maid -> maid_AIFFName) ) )
{
DeleteFile( (maid -> maid_AIFFName) );
}
#else
if( maid -> maid_8SVXObject )
{
/* Avoid that we free the sample data which belongs to the 8svx.datatype object */
SetDTAttrs( o, NULL, NULL, SDTA_Sample, NULL, TAG_DONE );
DisposeDTObject( (maid -> maid_8SVXObject) );
}
/* Delete tmp 8SVX file if we created one... */
if( strlen( (maid -> maid_8SVXName) ) )
{
DeleteFile( (maid -> maid_8SVXName) );
}
#endif /* USE_MPEGA */
/* Free outselves */
DoSuperMethodA( cl, o, msg );
/* Restore I/O error */
SetIoErr( saved_ioerr );
}
break;
case OM_UPDATE:
{
if( DoMethod( o, ICM_CHECKLOOP ) )
{
break;
}
}
case OM_SET:
{
/* Pass the attributes to the sound class and force a refresh if we need it */
if( retval = DoSuperMethodA( cl, o, msg ) )
{
/* The following check statement isn't needed because OM_NEW does not allow subclasses of mpegaudio.datatype,
* therefore, we're always the top instance...
*/
#ifdef COMMENTED_OUT
/* Top instance ? */
if( OCLASS( o ) == cl )
#endif /* COMMENTED_OUT */
{
struct RastPort *rp;
/* Get a pointer to the rastport */
if( rp = ObtainGIRPort( (((struct opSet *)msg) -> ops_GInfo) ) )
{
struct gpRender gpr;
/* Force a redraw */
gpr . MethodID = GM_RENDER;
gpr . gpr_GInfo = ((struct opSet *)msg) -> ops_GInfo;
gpr . gpr_RPort = rp;
gpr . gpr_Redraw = GREDRAW_UPDATE;
DoMethodA( o, (Msg)(&gpr) );
/* Release the temporary rastport */
ReleaseGIRPort( rp );
/* We did a refresh... */
retval = 0UL;
}
}
}
}
break;
/****** mpegaudio.datatype/DTM_WRITE **********************************************
*
* NAME
* DTM_WRITE -- Save data
*
* FUNCTION
* This method saves the object's contents to disk.
*
* If dtw_Mode is DTWM_IFF, the method is passed unchanged to the
* superclass, sound.datatype, which writes an IFF 8SVX sample.
*
* If dtw_mode is DTWM_RAW, the object writes a MPEG audio stream to
* the filehandle given.
* (If the class library was compiled with the NO_ENCODER switch
* (not the default), result == 0 and resul2 == ERROR_NOT_IMPLEMENTED
* are returned).
*
* TAGS
* None defined.
*
* RESULT
* Returns 0 for failure (IoErr() returns result2), non-zero
* for success.
*
******************************************************************************
*
*/
case DTM_WRITE:
{
struct dtWrite *dtw;
dtw = (struct dtWrite *)msg;
/* Local data format requested ? */
if( (dtw -> dtw_Mode) == DTWM_RAW )
{
/* Enable the followng code if you don't have an encoder implemented... */
#ifdef NO_ENCODER
SetIoErr( ERROR_NOT_IMPLEMENTED );
retval = 0UL;
#else
retval = SaveMPEGAudio( cb, o, dtw );
#endif /* NO_ENCODER */
}
else
{
/* Pass msg to superclass (which writes an IFF 8SVX sample)... */
retval = DoSuperMethodA( cl, o, msg );
}
}
break;
/* Let the superclass handle everything else */
default:
{
retval = DoSuperMethodA( cl, o, msg );
}
break;
}
return( retval );
}
static
LONG LoadSample( struct ClassBase *cb, Object *o )
{
struct MPEGAudioInstData *maid = (struct MPEGAudioInstData *)INST_DATA( (cb -> cb_Lib . cl_Class), o );
LONG error = 0L;
BPTR fh; /* stream handle */
ULONG sourcetype; /* type of stream (either DTST_FILE or DTST_RAM */
struct VoiceHeader *vh; /* obj's voice header */
/* Get file handle, handle type and VoiceHeader */
if( GetDTAttrs( o, DTA_SourceType, (&sourcetype),
DTA_Handle, (&fh),
SDTA_VoiceHeader, (&vh),
TAG_DONE ) == 3UL )
{
switch( sourcetype )
{
case DTST_FILE:
{
/* We got all what we want (a filehandle) */
}
break;
#ifndef NO_ENCODER
case DTST_RAM:
{
/* Do nothing... */
}
break;
#endif /* !NO_ENCODER */
default:
{
/* unsupported source type */
error = ERROR_NOT_IMPLEMENTED;
}
break;
}
/* Any error ? */
if( error == 0L )
{
#ifdef USE_MPEGA
if( fh )
{
TEXT pipe_in[ 256 ],
cmd[ 256 ];
BPTR mpega_in;
mysprintf( cb, pipe_in, "PIPE:MPEGAudio_in%lx", o );
mysprintf( cb, (maid -> maid_AIFFName), "T:MPEGAudio_tmp%lx.aiff", o );
mysprintf( cb, cmd, "mpega:mpega -A -d4 -q0 -r -s -i -u -m -D -C %s %s", pipe_in, (maid -> maid_AIFFName) );
if( mpega_in = Open( pipe_in, MODE_NEWFILE ) )
{
/* Start decoder "mpega" */
if( SystemTags( cmd, SYS_Input, Open( "CON:////MPEG Audio DataType/auto/close/wait/inactive", MODE_NEWFILE ),
SYS_Output, NULL,
SYS_Asynch, TRUE,
TAG_DONE ) == 0L )
{
UBYTE buffer[ 4096 ];
LONG numread;
/* Feed "mpega" with data (througth the pipe) */
do
{
if( (numread = Read( fh, buffer, sizeof( buffer ) )) != -1L )
{
(void)Write( mpega_in, buffer, numread );
}
} while( numread == sizeof( buffer ) );
}
else
{
/* can't start "mpega" */
error = IoErr();
}
Close( mpega_in );
}
else
{
/* can't open pipe */
error = IoErr();
}
/* Success ? */
if( error == 0L )
{
try:
maid -> maid_AIFFObject = NewDTObject( (maid -> maid_AIFFName), DTA_GroupID, GID_SOUND, TAG_DONE );
/* This may happen if "mpega" has not been finished yet,,, */
if( ((maid -> maid_AIFFObject) == NULL) && (IoErr() == ERROR_OBJECT_IN_USE) )
{
/* Wait a 1/2 sec */
Delay( (TICKS_PER_SECOND / 2UL) );
goto try;
}
if( maid -> maid_AIFFObject )
{
struct VoiceHeader *aiff_vh;
APTR aiff_sample;
ULONG aiff_samplelength;
ULONG aiff_period;
ULONG aiff_volume;
if( GetDTAttrs( (maid -> maid_AIFFObject), SDTA_VoiceHeader, (&aiff_vh),
SDTA_Sample, (&aiff_sample),
SDTA_SampleLength, (&aiff_samplelength),
SDTA_Period, (&aiff_period),
SDTA_Volume, (&aiff_volume),
TAG_DONE ) == 5UL )
{
/* Copy voiceheader. This point is very tricky because mpeg audio might not support all things... */
*vh = *aiff_vh;
/* Set misc attributes
* In fact, SDTA_Period and SDTA_Volume are calculated from SDTA_VoiceHeader info,
* but we set it here EXPLICITLY that noone can say we didn't pass this to sound.datatype...
*/
SetDTAttrs( o, NULL, NULL, SDTA_Sample, aiff_sample,
SDTA_SampleLength, aiff_samplelength,
SDTA_Period, aiff_period,
SDTA_Volume, aiff_volume,
TAG_DONE );
}
else
{
/* the object did not support all attributes we want... */
error = ERROR_OBJECT_WRONG_TYPE;
}
}
else
{
/* NewDTObject failed */
error = IoErr();
}
}
}
else
{
/* no filehandle */
error = ERROR_NO_FREE_STORE;
}
#else
if( fh )
{
BPTR stdout = Open( "CON:////MPEG Audio DataType/auto/close/wait/inactive", MODE_NEWFILE );
TEXT cmd[ 256 ];
/* The '@' character at the beginning of the input filename option
* means in my "maplay" version to use stdin as input
*/
mysprintf( cb, (maid -> maid_8SVXName), "@%lx.8svx", o );
mysprintf( cb, cmd, "maplay:maplay -v @%lx", o );
/* Start decoder "maplay" */
if( SystemTags( cmd, SYS_Input, fh,
SYS_Output, stdout,
NP_ConsoleTask, (((struct FileHandle *)BADDR( stdout )) -> fh_Type),
NP_StackSize, 16384UL,
TAG_DONE ) == 0L )
{
}
else
{
/* can't start "maplay" */
error = IoErr();
}
Close( stdout );
/* Success ? */
if( error == 0L )
{
try:
maid -> maid_8SVXObject = NewDTObject( (maid -> maid_8SVXName), DTA_GroupID, GID_SOUND, TAG_DONE );
/* This may happen if "maplay" has not been finished yet,,, */
if( ((maid -> maid_8SVXObject) == NULL) && (IoErr() == ERROR_OBJECT_IN_USE) )
{
/* Wait a 1/5 sec */
Delay( (TICKS_PER_SECOND / 5UL) );
goto try;
}
if( maid -> maid_8SVXObject )
{
struct VoiceHeader *iff8svx_vh;
APTR iff8svx_sample;
ULONG iff8svx_samplelength;
ULONG iff8svx_period;
ULONG iff8svx_volume;
if( GetDTAttrs( (maid -> maid_8SVXObject), SDTA_VoiceHeader, (&iff8svx_vh),
SDTA_Sample, (&iff8svx_sample),
SDTA_SampleLength, (&iff8svx_samplelength),
SDTA_Period, (&iff8svx_period),
SDTA_Volume, (&iff8svx_volume),
TAG_DONE ) == 5UL )
{
/* Copy voiceheader. This point is very tricky because mpeg audio might not support all things... */
*vh = *iff8svx_vh;
/* Set misc attributes
* In fact, SDTA_Period and SDTA_Volume are calculated from SDTA_VoiceHeader info,
* but we set it here EXPLICITLY that noone can say we didn't pass this to sound.datatype...
*/
SetDTAttrs( o, NULL, NULL, SDTA_Sample, iff8svx_sample,
SDTA_SampleLength, iff8svx_samplelength,
SDTA_Period, iff8svx_period,
SDTA_Volume, iff8svx_volume,
TAG_DONE );
}
else
{
/* the object did not support all attributes we want... */
error = ERROR_OBJECT_WRONG_TYPE;
}
}
else
{
/* NewDTObject failed */
error = IoErr();
}
}
}
else
{
/* no filehandle */
error = ERROR_NO_FREE_STORE;
}
#endif /* USE_MPEGA */
}
}
else
{
/* can't get required attributes from superclass */
error = ERROR_OBJECT_WRONG_TYPE;
}
return( error );
}
static
void mysprintf( struct ClassBase *cb, STRPTR buffer, STRPTR fmt, ... )
{
APTR args;
args = (APTR)((&fmt) + 1);
RawDoFmt( fmt, args, (void (*))"\x16\xc0\x4e\x75", buffer );
}
#ifndef NO_ENCODER
/* The MPEG Audio encoder */
static
ULONG SaveMPEGAudio( struct ClassBase *cb, Object *o, struct dtWrite *dtw )
{
ULONG retval = 0UL;
LONG error = ERROR_NOT_IMPLEMENTED;
#if 0
/* A NULL file handle is a nop (GMultiView uses this to test if a datatype supports RAW writing) */
if( dtw -> dtw_FileHandle )
{
}
#endif
/* Store Result2 */
SetIoErr( error );
return( retval );
}
#endif /* !NO_ENCODER */